/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.engine.core.be;

import com.inspur.edp.bef.api.be.IBusinessEntity;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.core.be.builtinimpls.BefBuiltInManager;
import com.inspur.edp.bef.core.be.builtinimpls.BefManagerCacheInfo;
import com.inspur.edp.bef.engine.api.IEngineBEManager;
import com.inspur.edp.bef.engine.common.GspBizEntityUtil;
import com.inspur.edp.bef.engine.core.BefEngineInfoCache;
import com.inspur.edp.bef.engine.core.dtm.BeforeQueryDtm;
import com.inspur.edp.bef.engine.core.dtm.BeforeRetrieveDtm;
import com.inspur.edp.bef.engine.entity.BeModelResInfo;
import com.inspur.edp.bef.engine.entity.serializer.EngineChangeDeserializer;
import com.inspur.edp.bef.engine.entity.serializer.EngineChangeSerializer;
import com.inspur.edp.bef.engine.entity.serializer.EngineRootDataDeserializer;
import com.inspur.edp.bef.spi.action.AbstractManagerAction;
import com.inspur.edp.bef.spi.entity.AbstractBizEntityDeSerializer;
import com.inspur.edp.bef.spi.entity.AbstractBizEntitySerializer;
import com.inspur.edp.bef.spi.entity.BefEntitySerConvertor;
import com.inspur.edp.cef.api.dataType.base.IAccessorCreator;
import com.inspur.edp.cef.entity.UQConstraintConfig;
import com.inspur.edp.cef.spi.determination.IEntityRTDtmAssembler;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefModelResInfoImpl;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefChangeJsonDeserializer;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefChangeSerializer;
import com.inspur.edp.cef.variable.api.manager.IVariableManager;
import com.inspur.edp.commonmodel.engine.api.common.CMEngineUtil;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.entity.object.GspUniqueConstraint;
import com.inspur.edp.das.commonmodel.util.CommonModelExtension;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo;
import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;

public class EngineBEManager extends BefBuiltInManager implements IEngineBEManager {

    private final GspBusinessEntity be;
    private GspMetadata metadata;
    private volatile HashMap<String, ArrayList<UQConstraintConfig>> constraintInfo;

    public EngineBEManager(GspBusinessEntity be) {
        this.be = be;
    }

    public EngineBEManager(GspBusinessEntity be, GspMetadata metadata) {
        this.be = be;
        this.metadata = metadata;
    }

    protected static BefManagerCacheInfo getManagerCacheInfo(GspBusinessEntity businessEntity) {
        GspMetadata metadata = CMEngineUtil.getMetadata(businessEntity.getID());
        if (metadata != null && metadata.getProperties() != null && metadata.getProperties().getCacheVersion() != null && !"".equals(metadata.getProperties().getCacheVersion())) {
            return BefEngineInfoCache.getBefEngineInfo(businessEntity.getID(), metadata.getProperties().getCacheVersion()).getManagerCacheInfo();
        } else {
            return BefEngineInfoCache.getBefEngineInfo(businessEntity.getID()).getManagerCacheInfo();
        }
    }

    public static CefModelResInfoImpl getCefModelResourceInfo(GspBusinessEntity businessEntity) {
        CefModelResInfoImpl cefModelResInfo = (CefModelResInfoImpl) getManagerCacheInfo(businessEntity).getModelResInfo();
        if (cefModelResInfo != null)
            return cefModelResInfo;

        BeModelResInfo resInfo = createResInfo(businessEntity);
        getManagerCacheInfo(businessEntity).setModelResInfo(resInfo);
        return resInfo;
    }

    public static BeModelResInfo createResInfo(GspBusinessEntity be) {
        GspMetadata metadata = CMEngineUtil.getMetadata(be.getId());
        String resMetaDataId = "";
        if (metadata.getRefs() != null) {
            for (MetadataReference reference : metadata.getRefs()) {
                if (reference.getDependentMetadata().getType().equals("ResourceMetadata")) {
                    resMetaDataId = reference.getDependentMetadata().getId();
                    break;
                }
            }
        }

        String su = CommonModelExtension.getSUCode(be);
        if (StringUtils.isEmpty(su)) {
            DevBasicBoInfo devBasicBoInfo = SpringBeanUtils.getBean(DevBasicInfoService.class)
                    .getDevBasicBoInfo(metadata.getHeader().getBizobjectID());
            if (devBasicBoInfo != null) {
                su = devBasicBoInfo.getSuCode();
                CommonModelExtension.setSUCode(be, su);
            }
        }
        BeModelResInfo resInfo = new BeModelResInfo(be, su, resMetaDataId);
        return resInfo;
    }

    @Override
    protected AbstractCefChangeSerializer getChangeSerializer() {
        return new EngineChangeSerializer(be, (CefEntityResInfoImpl) ((BeModelResInfo) getModelInfo()).getCustomResource(be.getMainObject().getCode()));
    }

    @Override
    protected AbstractCefChangeJsonDeserializer getChangeDeserializer() {
        return new EngineChangeDeserializer(be, (CefEntityResInfoImpl) ((BeModelResInfo) getModelInfo()).getCustomResource(be.getMainObject().getCode()), this.getBEType());
    }

    @Override
    public AbstractBizEntitySerializer getDataSerialize() {
        return new BefEntitySerConvertor(this.getCefModelResourceInfo().getRootNodeCode(), true, this.getBEInfo().getBEType(),
                (CefEntityResInfoImpl) this.getCefModelResourceInfo().getCustomResource(this.getCefModelResourceInfo().getRootNodeCode()));
//    return new EngineRootDataSerializer(be,
//        (CefEntityResInfoImpl) ((BeModelResInfo)getModelInfo()).getCustomResource(be.getMainObject().getCode()));
    }

    @Override
    public AbstractBizEntityDeSerializer getDataDeserizlier() {
        return new EngineRootDataDeserializer(be,
                (CefEntityResInfoImpl) ((BeModelResInfo) getModelInfo()).getCustomResource(be.getMainObject().getCode()));
    }

    @Override
    protected IBusinessEntity createBusinessEntity(String dataId) {
        return new EngineBusinessEntity(be, (BeModelResInfo) innerGetModelInfo(), dataId, metadata);
    }

    @Override
    public IAccessorCreator getAccessorCreator() {
        return new AccessorCreator(be, getCefModelResourceInfo());
    }

    @Override
    protected IVariableManager createVariableManager() {
        if (be.getVariables() == null || be.getVariables().getContainElements().isEmpty()) {
            return null;
        } else {
            return new com.inspur.edp.cef.variableengine.core.manager.EngineVariableManager(be.getVariables());
        }
    }

    @Override
    public Object executeCustomAction(String actionCode, Object... pars) {
        getBEManagerContext().checkAuthority(actionCode);
        AbstractManagerAction action = GspBizEntityUtil
                .instantiateMgrAction(be, actionCode, getBEManagerContext(), pars);
        return Execute(action);
    }

    @Override
    protected BefManagerCacheInfo getManagerCacheInfo() {
        if (metadata != null && metadata.getProperties() != null && metadata.getProperties().getCacheVersion() != null && !"".equals(metadata.getProperties().getCacheVersion())) {
            return BefEngineInfoCache.getBefEngineInfo(be.getID(), metadata.getProperties().getCacheVersion()).getManagerCacheInfo();
        } else {
            return BefEngineInfoCache.getBefEngineInfo(be.getID()).getManagerCacheInfo();
        }
    }

    @Override
    public CefModelResInfoImpl getCefModelResourceInfo() {
        if (this.getManagerCacheInfo().getModelResInfo() != null)
            return (CefModelResInfoImpl) this.getManagerCacheInfo().getModelResInfo();

        BeModelResInfo resInfo = createResInfo(be);
        this.getManagerCacheInfo().setModelResInfo(resInfo);
        return resInfo;
    }

    @Override
    public HashMap<String, ArrayList<UQConstraintConfig>> getConstraintInfo() {
        if (constraintInfo == null) {
            java.util.HashMap<String, java.util.ArrayList<com.inspur.edp.cef.entity.UQConstraintConfig>> dict = new java.util.HashMap<>();
            for (GspBizEntityObject gspBizEntityObject : be.getAllNodes()) {
                java.util.ArrayList<com.inspur.edp.cef.entity.UQConstraintConfig> list = new java.util.ArrayList<>();
                for (GspUniqueConstraint gspUniqueConstraint : gspBizEntityObject.getContainConstraints()) {
                    com.inspur.edp.cef.entity.UQConstraintConfig config = new com.inspur.edp.cef.entity.UQConstraintConfig();
                    java.util.ArrayList<String> fields = new java.util.ArrayList<>();
                    for (String element : gspUniqueConstraint.getElementList()) {
                        IGspCommonElement ele = gspBizEntityObject.findElement(element);
                        fields.add(ele.getLabelID());
                    }
                    config.setConstraintFields(fields);
//        CustomizationRtService mdService = BefDtBeanUtil.getCustomizationRtService();
//        GspMetadata metadata = mdService.getMetadata(gspBizEntityObject.getBelongModelID());
//        DevBasicInfoService devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class);
//        DevBasicBoInfo devBasicBoInfo = devBasicInfoService.getDevBasicBoInfo(metadata.getHeader().getBizobjectID());
//        String resMetaDataId = "";
//        for(MetadataReference reference:metadata.getRefs()){
//          if(reference.getDependentMetadata().getType() == "ResourceMetadata"){
//            resMetaDataId = reference.getDependentMetadata().getId();
//            break;
//          }
//        }
                    String msg = getModelInfo().getCustomResource(gspBizEntityObject.getCode())
                            .getUniqueConstraintMessage(gspUniqueConstraint.getCode());
                    if (msg == null || msg.isEmpty()) {
                        msg = gspUniqueConstraint.getConstraintMessage();
                    }
                    config.setMessage(msg);
                    list.add(config);
                }
                if (list.size() > 0) {
                    dict.put(gspBizEntityObject.getCode(), list);
                }
            }

            constraintInfo = dict;
        }
        return constraintInfo;
    }

    @Override
    protected IEntityRTDtmAssembler createBeforeQueryDtmAssembler() {
        return new BeforeQueryDtm(be.getMainObject());
    }

    @Override
    protected IEntityRTDtmAssembler createBeforeRetrieveDtmAssembler() {
        return new BeforeRetrieveDtm(be.getMainObject());
    }

}
